#ifndef __THREAD_POOL__
#define __THREAD_POOL__
#include <vector>
#include <queue>
#include <memory>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <functional>

// 实现一个信号量类
class Semaphore
{
public:
    Semaphore(int limit = 0) : _resLimit(limit) {}
    ~Semaphore() {}
    // 获取一个信号量资源
    void wait()
    {
        std::unique_lock<std::mutex> lock(_mtx);
        // 等待信号量有资源，没有资源就会阻塞
        // _cond.wait(lock,[&](){return _resLimit > 0;});
        _cond.wait(lock, [&]() -> bool
                   { return _resLimit > 0; }); // 等待，直到条件为真

        _resLimit--; // 消耗一个信号量资源
    }
    // 增加一个信号量资源
    void post()
    {
        std::unique_lock<std::mutex> lock(_mtx);
        _resLimit++;
        // 通知所有
        _cond.notify_all();
    }

private:
    int _resLimit;
    std::mutex _mtx;
    std::condition_variable _cond;
};

// Any类型 表示用户可以接受任意类型的数据
class Any
{
public:
    Any() = default;
    ~Any() = default;
    Any(const Any &) = delete;
    Any &operator=(const Any &) = delete;
    Any(Any &&) = default;
    Any &operator=(Any &&) = default;

    // 这个构造函数能让any接受任意其他类型的数据
    template <typename T>
    Any(T data) : _base(std::make_unique<Derive<T>>(data)) {}

    // 将Any对象中的类型提取出来
    template <typename T>
    T _cast()
    {
        // 将基类指针转为派生类指针
        Derive<T> *pd = dynamic_cast<Derive<T>>(_base.get());
        if (pd == nullptr)
        {
            throw "type is unmatch!";
        }
        return pd->_data;
    }

private:
    // 基类类型
    class Base
    {
    public:
        virtual ~Base() = default;
    };
    // 派生类
    template <typename T>
    class Derive : public Base
    {
    public:
        Derive(T data) : _data(data) {}
        T _data;
    };

private:
    std::unique_ptr<Base> _base;
};

// Task类型的前置声明
class Task;

// 实现提交到线程池的task完成之后的返回值类型 Result
class Result
{
public:
    Result(std::shared_ptr<Task> task, bool isValid = true);
    ~Result() = default;

private:
    Any _any;
    Semaphore _sem;              // 信号量
    std::shared_ptr<Task> _task; // 指向对应获取返回值的任务对象
    std::atomic_bool _isValid;   // 返回值是否有效
};

// 用户可以自定义任意类型，从Task继承，重写run方法。实现自定义任务处理。
class Task
{
public:
    virtual Any run() = 0;
};

// 两种模式
enum class PoolMode
{
    MODE_FIXED, // 固定线程数量
    MODE_CACHE  // 可动态增长
};

class Thread
{
public:
    using ThreadFunc = std::function<void()>;
    void start();

    Thread(ThreadFunc func);
    ~Thread();

private:
    ThreadFunc _func;
};
/**
 * example:
 * ThreadPool pool;
 * pool.start(4);
 * class MyTask : public Task
 * {
    public:
        void run()
        {
            //...
        }
 * }
 * pool.submitTask(std::make_shared<MyTask>())
 */
class ThreadPool
{
public:
    ThreadPool();
    ~ThreadPool();

    void start(int initThreadSize = 4); // 开始线程池
    void setMode(PoolMode mode);        // 设置线程的工作模式

    // 设置task任务队列上限的阈值
    void setTaskQueMaxThreshHold(int threshhold);

    // 给线程池提交任务
    Result submitTask(std::shared_ptr<Task> sp);

    ThreadPool(const ThreadPool &) = delete;
    ThreadPool &operator=(const ThreadPool &) = delete;

private:
    // 定义线程函数
    void threadFunc();

private:
    std::vector<std::unique_ptr<Thread>> _threads; // 线程列表
    size_t _initThreadSize;                        // 初始线程数量

    std::queue<std::shared_ptr<Task>> _taskQue; // 任务队列
    std::atomic_uint _taskSize;                 // 任务数量

    int _taskQueMaxThreshHold; // 任务数量阈值

    std::mutex _taskQueMtx; // 保证任务队列的线程安全

    std::condition_variable _notFull;  // 任务队列不满
    std::condition_variable _notEmpty; // 任务队列不空

    PoolMode _poolMode; // 线程池工作模式
};

#endif
